#include "stm32f10x.h"
#include "ws2812.h"
#include "string.h"

uint16_t LED_Data[WS2812_LED_DATA_LEN] = {0};
WS2812_LED_CTRL ws2812_led = {0xff,0,0,0};

void ws2812_Init(void)
{
#ifdef _USE_TIMER_CLK
	
	GPIO_InitTypeDef  GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef		WS2812_TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  			WS2812_TIM_OCInitStructure;
	DMA_InitTypeDef 			WS2812_DMA_InitStructure;

	RCC_APB2PeriphClockCmd(WS2812_GPIO_CLK, ENABLE);	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);	 
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

	GPIO_InitStructure.GPIO_Pin = WS2812_GPIO_PIN;				 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 		 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		
	GPIO_Init(WS2812_GPIO_PORT, &GPIO_InitStructure);					
	
	
	WS2812_TIM_TimeBaseStructure.TIM_Prescaler		=	0;
	WS2812_TIM_TimeBaseStructure.TIM_CounterMode	=	TIM_CounterMode_Up;	
	WS2812_TIM_TimeBaseStructure.TIM_Period			=	(SystemCoreClock/(WS2812_Freq*1000))-1;	//800K
	WS2812_TIM_TimeBaseStructure.TIM_ClockDivision	=	TIM_CKD_DIV1;
	TIM_TimeBaseInit(WS2812_TIM,&WS2812_TIM_TimeBaseStructure);
	
	WS2812_TIM_OCInitStructure.TIM_OCMode			=	TIM_OCMode_PWM1;
	WS2812_TIM_OCInitStructure.TIM_OutputState		=	TIM_OutputState_Enable;	
	WS2812_TIM_OCInitStructure.TIM_Pulse			= 	0;	
	WS2812_TIM_OCInitStructure.TIM_OCPolarity		=	TIM_OCPolarity_High;	//????:TIM???????
	
	TIM_OC3Init(WS2812_TIM,&WS2812_TIM_OCInitStructure);	//?????
	TIM_OC3PreloadConfig(WS2812_TIM,TIM_OCPreload_Enable);	//??TIM3?CCR3????????
	
	TIM_Cmd(WS2812_TIM,DISABLE);	//??TIM3 ??????????
	
	TIM_DMACmd(WS2812_TIM,TIM_DMA_CC3,ENABLE);		//??TIM2_CH3?DMA??(CC2????3)
	
	WS2812_DMA_InitStructure.DMA_PeripheralBaseAddr	=	(uint32_t)&(TIM3->CCR3);		//??DMA????
	WS2812_DMA_InitStructure.DMA_MemoryBaseAddr		=	(uint32_t)LED_Data;	
	WS2812_DMA_InitStructure.DMA_DIR				=	DMA_DIR_PeripheralDST;			//??:???SendBuff???ReceiveBuff 
	WS2812_DMA_InitStructure.DMA_BufferSize			=	WS2812_LED_DATA_LEN;			//??????DMA_BufferSize=SendBuffSize
	WS2812_DMA_InitStructure.DMA_PeripheralInc		=	DMA_PeripheralInc_Disable;		//ReceiveBuff????
	WS2812_DMA_InitStructure.DMA_MemoryInc			=	DMA_MemoryInc_Enable;			//SendBuff????
	WS2812_DMA_InitStructure.DMA_PeripheralDataSize	=	DMA_PeripheralDataSize_HalfWord;//ReceiveBuff????,16bit
	WS2812_DMA_InitStructure.DMA_MemoryDataSize		=	DMA_MemoryDataSize_HalfWord;	//SENDBUFF_SIZE????,16bit
	WS2812_DMA_InitStructure.DMA_Mode				=	DMA_Mode_Normal;				//DMA??:????(????)
	WS2812_DMA_InitStructure.DMA_Priority			=	DMA_Priority_Medium;			//???:?
	WS2812_DMA_InitStructure.DMA_M2M				=	DMA_M2M_Disable;				//????????
	
	DMA_Init(DMA1_Channel2,&WS2812_DMA_InitStructure);									//??DMA1?2??(???????????)
	DMA_Cmd(DMA1_Channel2,DISABLE);														//???DMA??
#else
	GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(WS2812_GPIO_CLK, ENABLE);	 

	GPIO_InitStructure.GPIO_Pin = WS2812_GPIO_PIN;				 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		
	GPIO_Init(WS2812_GPIO_PORT, &GPIO_InitStructure);		
	WS2812_LED_HIGH	();
#endif
	for (uint8_t idx = 0; idx < LED_NUMS ;idx ++)
		LED_Data[idx] = WS2812_LED_DATA_0;
//	memset(LED_Data,WS2812_LED_DATA_0,WS2812_LED_DATA_LEN - WS2812_RST_NUM);
	Change_WS2812LED_Status();	
}

void Fill_WS2812_LED_Data(uint8_t G,uint8_t R,uint8_t B,uint16_t Pos)
{
//	uint16_t temp[WS2812_LED_BIT] = {0};
//	uint8_t idx;
	uint32_t indexx=(Pos*WS2812_LED_BIT);
 
	if (Pos > LED_NUMS)
	{
		for (uint8_t idx = 0; idx < LED_NUMS ;idx ++)
			LED_Data[idx] = WS2812_LED_DATA_0;
	}
	else
	{
		for (uint8_t i = 0;i < 8;i++)
		{
			LED_Data[indexx+i]      = (G << i) & (0x80)?WS2812_LED_DATA_1:WS2812_LED_DATA_0;
			LED_Data[indexx+i + 8]  = (R << i) & (0x80)?WS2812_LED_DATA_1:WS2812_LED_DATA_0;
			LED_Data[indexx+i + 16] = (B << i) & (0x80)?WS2812_LED_DATA_1:WS2812_LED_DATA_0;
		}
	}
}

void WS2812_LED_PowerOff(void)
{
	for (uint8_t idx = 0; idx < LED_NUMS ;idx ++)
		LED_Data[idx] = WS2812_LED_DATA_0;
	Change_WS2812LED_Status();	
}

void WS2812_LED_Circle(void)
{
	uint16_t idx,i;
//	uint8_t level;
	
	for (idx = LED_NUMS - 1; idx > 0; idx --)
	{
		for (i = 0; i < WS2812_LED_BIT; i ++)
			LED_Data[idx* WS2812_LED_BIT  + i] = LED_Data[(idx-1) * WS2812_LED_BIT + i];
	}
	if (ws2812_led.phase < WS2812_LED_LEVEL)
	{
		ws2812_led.G -= (0xff / WS2812_LED_LEVEL);
		ws2812_led.R += (0xff / WS2812_LED_LEVEL);
		ws2812_led.phase ++;
		if (ws2812_led.phase == WS2812_LED_LEVEL)
		{
			ws2812_led.G = 0;
			ws2812_led.R = 0xff;
		}
	}
	else if (ws2812_led.phase < WS2812_LED_LEVEL * 2)
	{
		ws2812_led.R -= (0xff / WS2812_LED_LEVEL);
		ws2812_led.B += (0xff / WS2812_LED_LEVEL);
		ws2812_led.phase ++;
		if (ws2812_led.phase == WS2812_LED_LEVEL * 2)
		{
			ws2812_led.R = 0;
			ws2812_led.B = 0xff;
		}
	}
	else if (ws2812_led.phase < WS2812_LED_LEVEL * 3)
	{
		ws2812_led.B -= (0xff / WS2812_LED_LEVEL);
		ws2812_led.G += (0xff / WS2812_LED_LEVEL);
		ws2812_led.phase ++;
		if (ws2812_led.phase == WS2812_LED_LEVEL * 3)
		{
			ws2812_led.B = 0;
			ws2812_led.G = 0xff;
			ws2812_led.phase = 0;
		}
	}
	Fill_WS2812_LED_Data(ws2812_led.G,ws2812_led.R,ws2812_led.B,0);
	Change_WS2812LED_Status();
}



void WS2812_LED_RST(void)
{
#ifdef _USE_TIMER_CLK	
	TIM_Cmd(WS2812_TIM,DISABLE);
#endif	
	WS2812_LED_LOW();
	DelayUs(WS2812_RESET_TIME);
}



void Change_WS2812LED_Status(void)
{
#ifdef _USE_TIMER_CLK		
	DMA_SetCurrDataCounter(DMA1_Channel2,(WS2812_LED_DATA_LEN));
	DMA_Cmd(DMA1_Channel2,ENABLE);
	TIM_Cmd(WS2812_TIM,ENABLE);
	while(DMA_GetFlagStatus(DMA1_FLAG_TC2) != SET);
	DMA_Cmd(DMA1_Channel2,DISABLE);
	DMA_ClearFlag(DMA1_FLAG_TC2);
	TIM_Cmd(WS2812_TIM,DISABLE);
//	WS2812_LED_RST();
#else
	int i;
	for(i = 0;i < LED_NUMS;i++)
	{
		Write_One_RGBLED(LED_Data[3 * i],LED_Data[3 * i + 1],LED_Data[3 * i + 2]);
	}
	WS2812_LED_RST();
#endif	
}

